package com.yjzx.util.common.util.unmodifiable;

import com.yjzx.util.common.util.BeanUtils.LambdaField;
import com.yjzx.util.common.util.BeanUtils.LambdaFieldGetter;
import com.yjzx.util.common.util.BeanUtils.LambdaSerializable;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yjzx
 * @date 2024/8/26
 * @description UnmodifiableObjectBuilder
 */
public final class UnmodifiableObjBuilder {
    private final Set<Method> excludeMethods;
    private final Set<Method> includeMethods;

    private UnmodifiableObjBuilder() {
        excludeMethods = new HashSet<>();
        includeMethods = new HashSet<>();
    }

    public static UnmodifiableObjBuilder anUnmodifiableObject() {
        return new UnmodifiableObjBuilder();
    }

    public UnmodifiableObjBuilder excludeMethods(List<Method> excludeMethods) {
        this.excludeMethods.addAll(excludeMethods);
        return this;
    }
    public UnmodifiableObjBuilder includeMethods(List<Method> includeMethods) {
        this.includeMethods.addAll(includeMethods);
        return this;
    }

    public <V extends LambdaFieldGetter> UnmodifiableObjBuilder excludeMethodsLambda(List<V> lambdaMethods) {
        toAddAll(lambdaMethods, excludeMethods);
        return this;
    }
    public <V extends LambdaFieldGetter> UnmodifiableObjBuilder includeMethodsLambda(List<V> lambdaMethods) {
        toAddAll(lambdaMethods, includeMethods);
        return this;
    }

    public void toAddAll(List<? extends LambdaSerializable> lambdaMethods, Collection<Method> methods) {
        if (lambdaMethods != null && lambdaMethods.size() > 0) {
            LambdaSerializable serializable = lambdaMethods.get(0);
            List<Method> list = lambdaMethods.stream().map(x -> serializable instanceof LambdaField ?
                    ((LambdaField) x).getColumnSetterMethod() : x.getMethodFromLambda()).filter(Objects::nonNull).collect(Collectors.toList());
            methods.addAll(list);
        }
    }

    public UnmodifiableObject build() {
        return new UnmodifiableObject(new ArrayList<>(excludeMethods), new ArrayList<>(includeMethods));
    }
}
